﻿using System;
using System.Collections.Generic;
using Microsoft.SharePoint;
using Navigant.Infrastructure.Cases;
using Navigant.Infrastructure.DomainBase;
using Navigant.Infrastructure.Helpers;
using Navigant.Model.Cases;

namespace Navigant.Infrastructure.Repositories
{
    public class SharePointCaseRepository : ICaseRepository
    {
        #region Constants

        public static class Constants
        {
            public const string SiteSettingNameViewField = "LinkTitle";
            public const string SiteSettingNameField = "Title";
            public const string SiteSettingNumberValueField = "Number Value";
            public const string SiteSettingStringValueField = "String Value";
            public const string SiteSettingsListName = "Site Settings";
            public const string CustodiansListName = "Custodians";
            public const string ImagesListName = "Images";
            public const string PictureFileExtensionField = "Type";
            public const string PictureHeightField = "Picture Height";
            public const string PictureWidthField = "Picture Width";
        }

        #endregion

        #region ICaseRepository Members

        public ICase FindBy(Uri siteAddress)
        {
            using (SPSite site = new SPSite(siteAddress.AbsoluteUri))
            {
                return this.GetCaseFromSite(site);
            }
        }

        public ICase FindBy(Guid clientPortalId, Guid caseId)
        {
            Case caseSite = null;
            using (SPSite site = new SPSite(clientPortalId))
            {
                if (site.AllWebs[caseId] != null)
                {
                    using (SPWeb web = site.OpenWeb(caseId))
                    {
                        caseSite = this.GetCaseFromWeb(web);
                    }
                }
            }
            return caseSite;
        }

        public IList<HtmlImageData> FindAllImages(ICase currentCase)
        {
            List<HtmlImageData> images = new List<HtmlImageData>();
            using (SPSite site = new SPSite(currentCase.ClientPortalId))
            {
                using (SPWeb web = site.OpenWeb(currentCase.Id))
                {
                    SPPictureLibrary pictureLibrary = null;
                    try
                    {
                        pictureLibrary = (SPPictureLibrary)web.Lists[Constants.ImagesListName];
                    }
                    catch { }
                    if (pictureLibrary != null)
                    {
                        HtmlImageData image = null;
                        string type = string.Empty;
                        int height = 0;
                        int width = 0;
                        byte[] rawData = null;
                        foreach (SPListItem pictureItem in pictureLibrary.Items)
                        {
                            type = pictureItem[Constants.PictureFileExtensionField] != null ?
                                pictureItem[Constants.PictureFileExtensionField].ToString() : string.Empty;
                            height = pictureItem[Constants.PictureHeightField] != null ?
                                (int)pictureItem[Constants.PictureHeightField] : 0;
                            width = pictureItem[Constants.PictureWidthField] != null ?
                                (int)pictureItem[Constants.PictureWidthField] : 0;
                            rawData = pictureItem.File.OpenBinary(SPOpenBinaryOptions.SkipVirusScan);
                            image = new HtmlImageData(pictureItem.Name,
                                type, height, width, pictureItem.File.Url, rawData);
                            images.Add(image);
                        }
                    }
                }
                return images;
            }
        }

        public void SetSetting(ICase currentCase, string name, int numberValue)
        {
            using (SPSite site = new SPSite(currentCase.ClientPortalId))
            {
                using (SPWeb web = site.OpenWeb(currentCase.Id))
                {
                    SPListItemCollection settings = this.GetSettingsItems(web);
                    SPListItem settingToSet = null;
                    foreach (SPListItem setting in settings)
                    {
                        if (setting[Constants.SiteSettingNameField].ToString() == name)
                        {
                            settingToSet = setting;
                            break;
                        }
                    }
                    if (settingToSet == null)
                    {
                        settingToSet = settings.Add();
                        settingToSet[Constants.SiteSettingNameField] = name;
                    }

                    settingToSet[Constants.SiteSettingNumberValueField] = numberValue;
                    settingToSet.Update();
                }
            }
        }

        #endregion

        #region GetCaseFromSite

        private Case GetCaseFromSite(SPSite site)
        {
            Case caseSite = null;
            using (SPWeb web = site.OpenWeb())
            {
                caseSite = this.GetCaseFromWeb(web);
            }
            return caseSite;
        }

        #endregion

        #region GetCaseFromWeb

        private Case GetCaseFromWeb(SPWeb web)
        {
            Case caseSite = null;
            try
            {
                if (web == null)
                {
                    throw new ArgumentException("Must have a valid SPWeb instance", "web");
                }
                if (SharePointCaseRepository.IsValidCaseSite(web))
                {
                    // TDM:  changed to use the web.ID instead of the site.ID
                    caseSite = new Case(web.ID, web.Title, new Uri(web.Url), web.Site.ID);
                    this.LoadSiteSettings(web, caseSite);
                    this.LoadConfigurationSettings(caseSite);
                }
                else
                {
                    //Logger.LogMessage(string.Format("Could not retrieve Case from the following URL:  {0}.", 
                    //    web.Url));
                }
            }
            catch (Exception e)
            {
                Logger.LogError(e);
            }
            return caseSite;
        }

        #endregion

        #region IsValidCaseSite

        public static bool IsValidCaseSite(SPWeb web)
        {
            bool valid = false;
            foreach (SPList list in web.Lists)
            {
                if (list.Title == Constants.CustodiansListName)
                {
                    valid = true;
                    break;
                }
            }
            return valid;
        }

        #endregion

        #region LoadSiteSettings

        private void LoadSiteSettings(SPWeb web, ICase caseSite)
        {
            SPListItemCollection settings = this.GetSettingsItems(web);
            if (settings != null)
            {
                string name = string.Empty;
                int numberValue = 0;
                string stringValue = string.Empty;
                CaseSetting caseSetting = null;
                bool containsStringValueField = SharePointCaseRepository.ListContainsStringValueField(settings.List);

                foreach (SPListItem setting in settings)
                {
                    // Guard against null entries in the list
                    try
                    {
                        name = string.Empty;
                        if (setting[Constants.SiteSettingNameField] != null)
                        {
                            name = setting[Constants.SiteSettingNameField].ToString();
                        }

                        numberValue = 0;
                        if (setting[Constants.SiteSettingNumberValueField] != null)
                        {
                            numberValue = Convert.ToInt32(setting[Constants.SiteSettingNumberValueField]);
                        }

                        stringValue = string.Empty;
                        if (containsStringValueField && 
                            setting[Constants.SiteSettingStringValueField] != null)
                        {
                            stringValue = setting[Constants.SiteSettingStringValueField].ToString();
                        }

                        if (name.Length > 0)
                        {
                            caseSetting = new CaseSetting()
                            {
                                Name = name,
                                NumberValue = numberValue,
                                StringValue = stringValue
                            };
                            if (!caseSite.Settings.Contains(caseSetting))
                            {
                                caseSite.Settings.Add(caseSetting);
                            }
                        }
                    }
                    catch { }
                }
            }
        }

        #endregion

        #region LoadConfigurationSettings

        private void LoadConfigurationSettings(ICase caseSite)
        {
            foreach (CaseSetting setting in caseSite.Settings)
            {
                if (!string.IsNullOrEmpty(setting.Name) &&
                    !string.IsNullOrEmpty(setting.StringValue))
                {
                    caseSite.ConfigurationSettings.Add(setting.Name, setting.StringValue);
                }
            }
        }

        #endregion

        #region ListContainsStringValueField

        public static bool ListContainsStringValueField(SPList settings)
        {
            bool containsField = false;
            foreach (SPField field in settings.Fields)
            {
                if (field.Title == Constants.SiteSettingStringValueField ||
                    field.InternalName == Constants.SiteSettingStringValueField)
                {
                    containsField = true;
                    break;
                }
            }
            return containsField;
        }

        #endregion

        #region GetSettingsItems

        private SPListItemCollection GetSettingsItems(SPWeb web)
        {
            SPListItemCollection settings = null;
            try
            {
                settings = web.Lists[Constants.SiteSettingsListName].Items;
            }
            catch //(Exception e)
            {
                //Logger.LogError(e);
            }
            return settings;
        }

        #endregion
    }
}
